/**
 *********************************************************
 ** <h1>SFMLex - Simple and Fast Multimedia Library Extensions.</h1>
 ** SFMLex Copyright (C) 2008 Neil Johnson (neil@emailus.me.uk)
 ** 
 ** SFML - Simple and Fast Multimedia Library
 ** Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
 **
 ** This software is provided 'as-is', without any express or implied warranty.
 ** In no event will the authors be held liable for any damages arising from the use of this software.
 **
 ** Permission is granted to anyone to use this software for any purpose,
 ** including commercial applications, and to alter it and redistribute it freely,
 ** subject to the following restrictions:
 **
 ** 1. The origin of this software must not be misrepresented;
 **    you must not claim that you wrote the original software.
 **    If you use this software in a product, an acknowledgment
 **    in the product documentation would be appreciated but is not required.
 **
 ** 2. Altered source versions must be plainly marked as such,
 **    and must not be misrepresented as being the original software.
 **
 ** 3. This notice may not be removed or altered from any source distribution.
 **
 ************************************************************
 */
#ifndef SFX_C_ANIM_SPRITE_H
#define SFX_C_ANIM_SPRITE_H


#include <SFML/Graphics.hpp>
#include <vector>
#include <map>
#include <assert.h>

namespace sfx
{
   /**
    * An Animated Sprite Class.
    * This class extends the sf::Sprite class to
    * provide animation functionalty.
    */
   class c_AnimSprite : public sf::Sprite
   {
   public:
      
      /**
       * Enum of all possible animation modes.
       */
      enum e_AnimMode
      {
         d_ANIM_MODE_NONE,      /**< No animation, display frame selected by setFrame */
         d_ANIM_MODE_FWD_LOOP,  /**< Increment through animation frames. Loop by to start when end is reached */
         d_ANIM_MODE_REV_LOOP

      };
       
      /**
       * Overloaded Constructor.
       * A constructor allowing varions attributes to be specified.
       * @param Image Reference to Image used.
       * @param FPS   Initial animation frames per second.
       * @param NumFrames Initial num of frames of size (FrameWidth, FrameHeight).
       * @param FrameWidth Initial animation frame width.
       * @param FrameHeight Initial animation frame height.
       * @param Position Position of the sprite (0, 0 by default)
       * @param Scale Scale factor (1, 1 by default) 
       * @param Roataion Orientation, in degrees (0 by default) 
       * @param Color Colour of animated sprite. ( 255, 255, 255, 255 ) by default
       */
      c_AnimSprite( const sf::Image& Image,
                    unsigned int       NumFrames,
                    e_AnimMode         Mode,
                    float              FPS,
                    unsigned int       FrameWidth,
                    unsigned int       FrameHeight = 0,
                    const sf::Vector2f Position = sf::Vector2f( 0, 0 ),
                    const sf::Vector2f Scale    = sf::Vector2f( 1, 1 ),
                    float              Roataion = 0.0f,
                    const sf::Color    Color    = sf::Color( 255, 255, 255, 255 )
                    );
      
      
      /**
       * Method to allow specific frame to be displayed.
       * @param FrameNumber Animation Frame to be displayed.
       */
      void setCurrentFrame( unsigned int FrameNumber );
      
      /**
       * Method to create a named animation sequence.
       * @param Name
       * @param Mode
       * @param FPS
       * @param Sequence
       * @return true if sucessfull.
       */
      bool createSequence( const std::string&           Name, 
                           e_AnimMode                   Mode,
                           float                        FPS,
                           std::vector< unsigned int >& Sequence );

      /**
       * Sets the current sequence to the supplied name
       * @param Name of sequence to make current
       */
      void setCurrentSequence( const std::string& SequenceName );

      /**
       * Update Animation.
       * This function should be called during the main game loop in order to update animation.
       */
      void update( void )
      {
         assert( m_CurrentSequence );

         m_CurrentSequence->update( m_TimeDelta );
      }
      
      /**
       * Class method to allow time since last update to be specified.
       * This should be called with the time in seconds since the last animation update.
       */
      static void setUpdateDelta( float TimeDelta )
      {
         m_TimeDelta = TimeDelta;
      }
        
      
      /**
       * Destructor
       */
      virtual ~c_AnimSprite(void);
      
   private:
      /**
       * Default constructor.
       */
      c_AnimSprite(void);


   private:
      
      /**
       * Animation sequence.
       * Small class that encapsulates an animation sequence throght a set of frames
       */
      class c_AnimSequence
      {
      public:
         c_AnimSequence( c_AnimSprite*                      AnimSprite,
                         const std::string&                 Name,
                         c_AnimSprite::e_AnimMode           Mode,
                         float                              FPS,
                         const std::vector< unsigned int >& Sequence );
            
         ~c_AnimSequence()
         {
         }
      
         void update( float UpdateDelta );

      private:
         void initSequence( void );
         
      private:
         c_AnimSprite*               m_AnimSprite;
         std::string                 m_Name;
         c_AnimSprite::e_AnimMode    m_Mode;
         float                       m_FPS;
         std::vector< unsigned int > m_FrameSequence;
         float                       m_FrameTime;
         float                       m_CurrentFrameTime;

         int                         m_CurrentFrame;
         int                         m_FrameSequenceDir;
      };

   private:
      
      /**
       * Method to clear sub rect list.
       */
      void clearFrames( void );
      
      /**
       * Adds supplied animation sequence to internal hash with name key.
       * @param SequenceName Name associated to this animation sequence.
       * @param Sequence     Pointer to an animation sequence object
       */
      void addSequence( const std::string& SequenceName, c_AnimSequence* Sequence );
      
      
      
      /**
       * Method to auto generate animation frames based on supplied parameters.
       */
      bool generateFrames( unsigned int FrameCount, unsigned int FrameWidth, unsigned int FrameHeight = 0 );

   private:

      std::vector< sf::IntRect* > m_Frames;     /**< All possible animation frames go here */
      
      c_AnimSequence* m_CurrentSequence;        /**< Current animation sequence */

      typedef std::map< std::string, c_AnimSequence* > t_AnimSequenceMap;
      t_AnimSequenceMap m_AnimSequenceMap;      /**< Maps names to animation sequences */

   private:
      static float m_TimeDelta;          /**< Update call delta.
                                              Time in seconds since last call to update. See by setUpdateDelta */

      static const std::string m_DefaultSequenceName;

      
   };

}

#endif //SFX_C_ANIM_SPRITE_H

